#include <iostream>
#include <thread>

#include "stock/sz_request.h"
#include "curl_http/curl_http.h"
#include "mysql_opt/mysqlx_opt.h"
#include "stock/common.h"
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "log_manger.h"

namespace bm
{
log_manger s_log_manger("log");
}

std::shared_ptr<mysqlx_opt> g_mysqlx_opt_ptr;
// mysqlx_opt g_mysqlx_opt("192.168.3.18", 33060, "root", "123456");
void get_stock_data()
{
    int pag_no = 1;
    int pag_count = 1;
    for(;pag_no <= pag_count; pag_no++)
    {
        if(!g_mysqlx_opt_ptr->connected())
        {
            BMLOG(ERROR) << "mysql not connect" << std::endl;
            std::cout << "mysql not connect!" << std::endl;
            break;
        }
        int64_t start = bm::time::get_current_timestamp();

        std::vector<std::string> codes;
        if(!sz::get_stock_lists(pag_no, pag_count, codes))
        {
            BMLOG(ERROR) << "get_stock_lists error!" << std::endl;
            std::cout << pag_no << " get_stock_lists error!" << std::endl;
        }
        std::vector<std::string> sqls;
        for(auto code : codes)
        {
            sz::get_stock_time_data(code, sqls);
        }

        // g_mysqlx_opt_ptr->execute("begin;");
        
        for(auto sql : sqls)
        {
            auto t1 = bm::time::get_current_timestamp();
            try{
                // std::cout << sql << std::endl;
                if(g_mysqlx_opt_ptr->execute(sql).getAffectedItemsCount() <= 0)
                {
                    // g_mysqlx_opt_ptr->execute("rollback;");
                    break;
                }
            }
            catch (const mysqlx::Error &err)
            { BMLOG(ERROR) << "mysql EXCEPTION:" << err << " sql:" << sql << std::endl; }
            catch (std::exception &ex)
            { BMLOG(ERROR) <<"STD EXCEPTION: " << ex.what() << " sql:" << sql << std::endl; }
            catch (const char *ex)
            { BMLOG(ERROR) <<"EXCEPTION: " << ex << " sql:" << sql << std::endl; }
            catch (...) { BMLOG(ERROR) << "UNKNOW EXCEPTION!" << " sql:" << sql << std::endl; }
            auto t2 = bm::time::get_current_timestamp();
            // std::cout << "mysql exec use time:" << t2 - t1 << " ms" << std::endl;
        }
        // g_mysqlx_opt_ptr->execute("commit;");
        if(!codes.empty())
        {
            int64_t end = bm::time::get_current_timestamp();
            std::cout << "pagno=" << pag_no << ",pag_count=" << pag_count << ",complate start "
            << codes.at(0) << " to " << codes.at(codes.size() - 1) << " data pull! use time=" 
            << end - start << "ms" << std::endl;
            BMLOG(INFO) << "pagno=" << pag_no << ",pag_count=" << pag_count << ",complate start "
            << codes.at(0) << " to " << codes.at(codes.size() - 1) << " data pull! use time=" 
            << end - start << "ms" << std::endl;
        }

    }
}
void init_mysql()
{
    std::string config = bm::file::read_file("config.json");
    rapidjson::Document d;
    d.Parse(config.c_str());

    std::string ip          = d["ip"].GetString();
    int port                = d["port"].GetInt();
    std::string username    = d["username"].GetString();
    std::string pwd         = d["pwd"].GetString();
    std::string db_name     = d["db_name"].GetString();

    g_mysqlx_opt_ptr = std::make_shared<mysqlx_opt>(ip, port, username, pwd, db_name);
}
std::string get_stock_date()
{
    std::string sql = "SELECT date_format(MAX(`date`), '%Y-%m-%d') FROM t_day_data;";
    try{
        auto r = g_mysqlx_opt_ptr->execute(sql);
        if(r.hasData())
        {
            // mysqlx::string ti = r.fetchOne().get(0);
            auto rows = r.fetchAll();
            for(auto row : rows)
            {
                mysqlx::string ti = row.get(0);
                std::string tii = ti;
                if(!tii.empty())
                    return tii;
            }
            // std::string tii = ti;
            return "";
        }
    }
    catch (const mysqlx::Error &err)
    { std::cout << "mysql EXCEPTION:" << err << " sql:" << sql << std::endl; }
    catch (std::exception &ex)
    { std::cout <<"STD EXCEPTION: " << ex.what() << " sql:" << sql << std::endl; }
    catch (const char *ex)
    { std::cout <<"EXCEPTION: " << ex << " sql:" << sql << std::endl; }
    catch (...) { std::cout << "UNKNOW EXCEPTION!" << " sql:" << sql << std::endl; }

    return "";
}
int main()
{
    bm::http::init_curl();
    init_mysql();
    
    bool is_pull_data = false;
    // bool today_has_pull_data = false;
    std::string today;
    int sleep_time = 1 * 60 * 1000;
    while(true)
    {
        std::string curr_database_stock_date = get_stock_date();
        std::string dt = bm::time::get_current_date();
        std::string curr_date = dt + " 15:30:00";
        std::string ct = bm::time::get_current_time();
        std::string pdt = bm::time::get_pre_date();
        // std::string pdt_date = pdt + " 15:30:00";
        if(curr_database_stock_date.empty())
            curr_database_stock_date = pdt;

        std::cout << curr_database_stock_date << "," << pdt << std::endl;
        if(ct < "15:30:00" && curr_database_stock_date < pdt && !is_pull_data)
        {
            is_pull_data = true;
            get_stock_data();
            // today_has_pull_data = true;
            is_pull_data = false;
        }
        else if(ct >= "15:30:00" && curr_database_stock_date < curr_date && !is_pull_data)
        {
            is_pull_data = true;
            get_stock_data();
            // today_has_pull_data = true;
            is_pull_data = false;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
    }
    // sz::get_stock_time_data("000048");
    bm::http::release_curl();
    return 0;
}